// bean header
#include "includes/BEAN.h"

////////////////////////////
// ENUM WITH PROGRAM ACTIONS
typedef enum
{
  // nothing to do
  NOTHING_TO_DO,
    
  // checking
  CHECK_ANIM,             // check if anim file has a correct structure
  CHECK_MODEL,            // check if model file has a correct structure
  CHECK_ANIM_WITH_MODEL,  // check if anim file (either CSV or BIN) and binary model file are related
    
  // reading
  READ_ANIM,              // read anim file (either CSV or BIN)
  READ_MODEL,             // read binary model file
  READ_ANIM_WITH_MODEL,   // read both anim file (either CSV or BIN) and binary model file
    
  // converting
  CONVERT_CSV_ANIM_TO_BIN_ANIM,   // convert csv anim file smax_to bin anim file
  CONVERT_BIN_ANIM_TO_CSV_ANIM,   // convert bin anim file smax_to csv anim file
    
  // side stuff
  EXTRACT_MODEL_TEXTURES,
} P_ACTION;


//////////////////////////
// PROGRAM ACTION VARIABLE
P_ACTION ACTION = NOTHING_TO_DO;


////////////////////////
// VALID COMMAND STRINGS
char_t ANIM_INPUT_ARG[] = "-anim";
char_t MODEL_INPUT_ARG[] = "-model";
char_t READ_FILE_ARG[] = "-read";
char_t CHECK_FILE_ARG[] = "-check";
char_t CONVERT_FILE_ARG[] = "-convert";
char_t CONVERT_TO_CSV[] = "csv";
char_t CONVERT_TO_BIN[] = "bin";
char_t EXTRACT_TEXTURES[] = "--extract-bti";


// functions only used on main.c
void display_help(void);
void check_command(char_t, char_t * []);
bool_t is_bin_btp(char_t * file_path);
smax_t is_anim(char_t *);
void read_anim(char_t *);


////////////////
// MAIN FUNCTION
int main(int argc, char * argv[])
{    
  // first, check system endianness
  CHECK_SYS_ENDIAN();
  
  // don't want to deal with warnnings
  // I only want to work with bytes 
  // (I will handle manually the sign)
  smax_t arg_count = (smax_t) argc;
  char_t ** arg_vector = (char_t **) argv;
  
  // check command and get program action
  check_command(arg_count, arg_vector);
  
  // another epic switch statement
  switch(ACTION)
  {
    /////////////////////////////////////////
    // ./a.out -model mario.bdl --extract-bti
    case(EXTRACT_MODEL_TEXTURES):
      EXTRACT_MODEL_BTI(arg_vector[2]);
      break;
    
    ////////////////////////////////////
    // ./a.out -anim iceflick.btp -check
    case(CHECK_ANIM):
      PRINT_BIN_BTP_CHECK(arg_vector[2]);
      break;
    
    //////////////////////////////////
    // ./a.out -model mario.bdl -check
    case(CHECK_MODEL):
      PRINT_MODEL_CHECK(arg_vector[2]);
      break;
    
    ///////////////////////////////////
    // ./a.out -anim iceflick.btp -read
    case(READ_ANIM):
      PRINT_BIN_BTP_CHECK(arg_vector[2]);
      PRINT_BIN_BTP_PTR_TB(arg_vector[2]);
      break;
    
    /////////////////////////////////  
    // ./a.out -model mario.bdl -read
    case(READ_MODEL):
      PRINT_MODEL_CHECK(arg_vector[2]);
      PRINT_MODEL_PTR_TB(arg_vector[2]);
      break; 
    
    /////////////////////////////////////////////////////
    // ./a.out -anim iceflick.btp -model mario.bdl -check
    case(CHECK_ANIM_WITH_MODEL):
      
      // check anim file and model file
      PRINT_MODEL_CHECK(arg_vector[4]);
      PRINT_BIN_BTP_CHECK(arg_vector[2]);
    
      // decide what to do with the anim file type
      if (GET_BIN_BTP_TYPE(arg_vector[2]) == BIN_BTP_TYPE)
        if (CHECK_BIN_BTP_WITH_BMD_BDL(arg_vector[2], arg_vector[4]) == false)
          exit(1);
      //~ else if (ANIM_TYPE == CSV_BTP_TYPE) {
        //~ if (CHECK_CSV_BTP_WITH_BMD_BDL(arg_vector[2], arg_vector[4]) == false)
          //~ exit(1);
      //~ }
      break; 
    
    ////////////////////////////////////////////////////
    // ./a.out -anim iceflick.btp -model mario.bdl -read
    case(READ_ANIM_WITH_MODEL):
      
      // check anim file and model file
      PRINT_MODEL_CHECK(arg_vector[4]);
      PRINT_BIN_BTP_CHECK(arg_vector[2]);
      
      // read both files
      PRINT_MODEL_PTR_TB(arg_vector[4]);
      PRINT_BIN_BTP_PTR_TB(arg_vector[2]);
      break;
    
    ///////////////////////////////////////////////////////////
    // ./a.out -anim iceflick.btp -convert csv
    // ./a.out -anim iceflick.btp -model mario.bdl -convert csv
    case(CONVERT_BIN_ANIM_TO_CSV_ANIM):
      
      // if model is provided check if both anim and model files are related      
      PRINT_BIN_BTP_CHECK(arg_vector[2]);
      
      // check if the file is actually valid for conversion
      if (GET_BIN_BTP_TYPE(arg_vector[2]) != BIN_BTP_TYPE) {
        printf("\nCannot convert CSV file to CSV file.\nTerminating program.\n");
        exit(1);
      }
      
      // model is provided
      if (arg_count == 7)
      {      
        // decide what to do with the anim file type
        if (GET_BIN_BTP_TYPE(arg_vector[2]) == BIN_BTP_TYPE)
        {
          if (CHECK_BIN_BTP_WITH_BMD_BDL(arg_vector[2], arg_vector[4]) == false)
            exit(1);          
        }
      }
      WRITE_CSV_BTP(arg_vector[2]);
      break;
    
    //~ ///////////////////////////////////////////////////////////////
    //~ // ./a.out -anim iceflick.btp.csv -model mario.bdl -convert bin
    //~ case(CONVERT_CSV_ANIM_TO_BIN_ANIM):
    
      //~ // check anim file
      //~ is_anim(arg_vector[2]);
      
      //~ // check if the file is actually valid for conversion
      //~ if (ANIM_TYPE == BIN_BTP_TYPE)
      //~ {
        //~ printf("\nCannot convert BIN file smax_to BIN file.\nTerminating program.\n");
        //~ exit(1);
      //~ }
      
      //~ // check model file           
      //~ is_model(arg_vector[4]);
        
      //~ // decide what to do with the anim file type
      //~ if (ANIM_TYPE == CSV_BTP_TYPE)
      //~ {
        //~ if (CHECK_CSV_BTP_WITH_BMD_BDL(arg_vector[2], arg_vector[4]) == false)
          //~ exit(1);
      //~ }
      
      //~ // write csv animation file
      //~ WRITE_BIN_BTP(arg_vector[2], arg_vector[4]);
      //~ break;
    
    ///////
    // how?
    default:
      printf("How on earth you managed to get here?\n");
      break;
  }
  
  // program end
  return 0;
}


//////////////////////////
// display_help() function
// function used to display program usage in case
// user inputs wrong information to the program.
// Also terminates the program session.
void display_help(void)
{
  // display some help  
  printf("Mateee... I dunnae know what to do with that command <:[\n");
  printf("Try again after these command examples:\n");
  
  printf("\n### Extract BTIs from model file\n");
  printf("bean -model mario.bdl --extract-bti\n");
  
  printf("\n### Check model file\n");
  printf("bean -model mario.bdl -check\n");
  
  printf("\n### Check anim file\n");
  printf("bean -anim iceflick.btp -check\n");
  
  printf("\n### Read model file file\n");
  printf("bean -model mario.bdl -read\n");
  
  printf("\n### Read anim file file\n");
  printf("bean -anim iceflick.btp -read\n");
  
  printf("\n### Convert a BIN anim file smax_to a CSV (NOT providing a model file)\n");
  printf("bean -anim iceflick.btp -convert csv\n");
  
  printf("\n### Read both an anim file and a model file\n");
  printf("bean -anim iceflick.btp -model mario.bdl -read\n");
  
  printf("\n### Check if an anim file and a model file are related\n");
  printf("bean -anim iceflick.btp -model mario.bdl -check\n");
  
  printf("\n### Convert a BIN anim file smax_to a CSV (providing a model file)\n");
  printf("bean -anim iceflick.btp -model mario.bdl -convert csv\n");
  
  printf("\n### Convert a CSV anim file smax_to a BIN (providing a model file)\n");
  printf("bean -anim iceflick.btp.csv -model mario.bdl -convert bin\n");
  
  // incorrect command exit
  exit(1);
}


///////////////////////////
// check_command() function
// function used to check if command 
// entered by the user is valid. Will
// call display_help() in case it isn't.
void check_command(char_t arg_count, char_t * arg_vector[])
{  
  // huge and epic switch statement >:]
  switch (arg_count)
  {
    // - checking a single file (anim or model)
    // - reading a single file (anim or model)
    
    // ./a.out -model mario.bdl -check
    // ./a.out -anim iceflick.btp -read
    
    case(4):      
      
      // checking an anim file
      if (compare_strings(arg_vector[1], ANIM_INPUT_ARG, 0) && compare_strings(arg_vector[3], CHECK_FILE_ARG, 0))
        ACTION = CHECK_ANIM;
      // checking a model file
      else if (compare_strings(arg_vector[1], MODEL_INPUT_ARG, 0) && compare_strings(arg_vector[3], CHECK_FILE_ARG, 0))
        ACTION = CHECK_MODEL;
      // reading an anim file
      else if (compare_strings(arg_vector[1], ANIM_INPUT_ARG, 0) && compare_strings(arg_vector[3], READ_FILE_ARG, 0))
        ACTION = READ_ANIM;
      // reading an model file
      else if (compare_strings(arg_vector[1], MODEL_INPUT_ARG, 0) && compare_strings(arg_vector[3], READ_FILE_ARG, 0))
        ACTION = READ_MODEL;
      // invalid command
      else if (compare_strings(arg_vector[1], MODEL_INPUT_ARG, 0) && compare_strings(arg_vector[3], EXTRACT_TEXTURES, 0))
        ACTION = EXTRACT_MODEL_TEXTURES;
      // invalid command
      else
        ACTION = NOTHING_TO_DO;
        
      break;
    
    // - converting a bin anim file smax_to csv (without providing model file)
    
    // ./a.out -anim iceflick.btp -convert csv
    
    case(5):
      
      // converting a bin anim file smax_to csv
      if (compare_strings(arg_vector[1], ANIM_INPUT_ARG, 0) &&
          compare_strings(arg_vector[3], CONVERT_FILE_ARG, 0) &&
          compare_strings(arg_vector[4], CONVERT_TO_CSV, 0))
        ACTION = CONVERT_BIN_ANIM_TO_CSV_ANIM;
      // invalid command
      else
        ACTION = NOTHING_TO_DO;
    
      break;
    
    // - checking if an anim file and a model file relate
    // - reading both an anim file and a model file (don't check if they relate)
    
    // ./a.out -anim iceflick.btp -model mario.bdl -read
    // ./a.out -anim iceflick.btp -model mario.bdl -check
    
    case(6):
    
      if (compare_strings(arg_vector[1], ANIM_INPUT_ARG, 0) &&
          compare_strings(arg_vector[3], MODEL_INPUT_ARG, 0))
      {
        // read both anim and model files
        if (compare_strings(arg_vector[5], READ_FILE_ARG, 0))
          ACTION = READ_ANIM_WITH_MODEL;
        // check if both anim and model files are related
        else if (compare_strings(arg_vector[5], CHECK_FILE_ARG, 0))
          ACTION = CHECK_ANIM_WITH_MODEL;
        // invalid command
        else
          ACTION = NOTHING_TO_DO;
      }
      // invalid command
      else
        ACTION = NOTHING_TO_DO;
    
      break;
    
    // - converting a binary anim file smax_to a csv file (providing model file)
    // - converting a csv anim file smax_to a bin file (providing model file)
    
    // ./a.out -anim iceflick.btp -model mario.bdl -convert csv
    // ./a.out -anim iceflick.btp.csv -model mario.bdl -convert bin
    
    case(7):
      
      if (compare_strings(arg_vector[1], ANIM_INPUT_ARG, 0) &&
          compare_strings(arg_vector[3], MODEL_INPUT_ARG, 0) &&
          compare_strings(arg_vector[5], CONVERT_FILE_ARG, 0))
      {
        // convert to csv
        if (compare_strings(arg_vector[6], CONVERT_TO_CSV, 0))
          ACTION = CONVERT_BIN_ANIM_TO_CSV_ANIM;
        // convert to bin
        else if (compare_strings(arg_vector[6], CONVERT_TO_BIN, 0))
          ACTION = CONVERT_CSV_ANIM_TO_BIN_ANIM;
        // invalid command
        else
          ACTION = NOTHING_TO_DO;
      }
      // invalid command
      else
        ACTION = NOTHING_TO_DO;
      
      break;
      
    default:
      ACTION = NOTHING_TO_DO;
      break;
  }
  
  if (ACTION == NOTHING_TO_DO)
    display_help();
}


// is_bin_btp() function
// function used to check if a file is a BIN BTP file
bool_t is_bin_btp(char_t * file_path)
{
  // first check if the file is valid
  Jbtp * btp = OPEN_BIN_BTP(file_path);
  CLOSE_BIN_BTP(btp);
  
  if (btp == NULL)
    return false;
  // all is good
  return true;
}


// is_anim() function
// function used to check if a file is a correct anim file
smax_t is_anim(char_t * anim_file_path)
{    
  // get file extension
  char_t * file_ext = get_file_ext(anim_file_path);
  
  //~ // CSV file check
  //~ if (compare_strings(file_ext, FILE_EXT[0], 0))
    //~ ANIM_TYPE = GET_CSV_TYPE(anim_file_path);
  // BIN BTP check
  if (compare_strings(file_ext, FILE_EXT[3], 0))
    return is_bin_btp(anim_file_path);
  
  // not an anim file
  return false;
}


///////////////////////
// read_anim() function
// function to read an anim file based on the anim file type
void read_anim(char_t * anim_file_path)
{  
  // decide what to do with the anim file type
  if (GET_BIN_BTP_TYPE(anim_file_path) == BIN_BTP_TYPE)
    PRINT_BIN_BTP_PTR_TB(anim_file_path);
  //~ else if (ANIM_TYPE == CSV_BTP_TYPE)
    //~ PRINT_CSV_BTP_STRUCT(anim_file_path);
}
